package com.cskaoyan.javase.oop1._6constructor;

/**
 * @description: 构造方法
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * > 创建一个教师类，有课程和年龄两个属性，行为是可以上课
 * - 思考一下，我们给成员变量赋值的语句，是不是显得冗余？
 * - 怎么改进？
 * - 对象的属性，能不能"出厂"的时候就设定好呢？
 *
 * 办法是有的:
 *      1.可以用显式赋值,可以近似的实现功能,但是它不够灵活,创建出来的每个对象的属性的初始值都是一样
 *          这仍然不是我们想要的方式
 *      2.需要使用构造器来完成成员变量的赋值
 *
 * 什么是构造器(构造方法\构造函数\constructor)
 *      在java语法中,任何使用new关键字创建对象都会调用构造器,构造器是用来给成员变量赋值的
 *      构造方法是类中的一种特殊方法，用来创建对象（实例）
 * 构造器的语法:
 *      [访问权限修饰符] 类名(参数){
 * 	        //方法体
 *      }
 * 访问权限修饰符实际上可以不写,默认情况下它是public
 * 类名可以认为是构造器的名字,它必须和类名保持完完全全一致(不能有任何差异)
 * 参数列表可以为空,也可以有参数
 * 构造器的方法体有标准的书写格式,方法体中用来写成员变量的赋值语句
 *
 * 使用构造器的注意事项:
 *      1.构造器是一种特殊的方法,它的语法和普通方法的语法有很大的差异.它们的调用也有很大差异
 *          构造器的调用不是由程序员完成的,而是JVM在创建对象时自动调用的
 *          构造器不是给程序员用的
 *      2.程序员虽然不直接调用构造器,但是可以指示JVM去调用哪个构造器完成对象的创建
 *          指示JVM调用某个构造器的语法是: new 某个构造器
 *      3.我们使用new关键字时,根据构造器的参数来区分不同的构造器
 *      4.当一个类中没有明确提供任何构造器时,Java会默认提供一个默认构造器,也叫无参构造器
 *          它的格式是:
 *          public 类名(){
 *          }
 *
 *      5.无参构造只能创建对象,但是不能赋值.如果想要给成员变量赋值,需要有参构造器
 *          在构造器当中也可以使用this关键字去区分同名的局部变量和成员变量
 *          构造器中也有隐含的this传参,指向当前对象
 *
 *      6.构造器的作用就是给成员变量赋值,在成员变量赋值方面,它是专业的(使用构造器给成员变量赋值,它的赋值一定是准确的)
 *      在各种各样的给成员变量赋值的方式中,构造器永远是最后执行的,如果是标准格式书写的构造器,它的赋值一定是准确的
 *      标准格式构造器:
 *          public 类名(参数){
 *              this.成员变量名 = 参数;
 *              ....
 *          }
 *      标准格式的构造器,可以用快捷键快速生成,ALT + insert
 *
 *      7.在成员变量有显式赋值,默认初始化,构造器赋值三种赋值方式的时候,它们的执行顺序是:
 *          1.默认初始化
 *          2.显式赋值
 *          3.构造器
 *        在以上赋值顺序中,默认初始化永远最先执行,构造器永远最后执行,我们在学习成员变量的赋值时,要"掐头去尾",实际上学习它是很简单的
 *
 *      8.无参/默认构造器只有在一个类没有任何构造器时才会提供,如果一个类有任何一个构造器就不会再提供默认构造器
 *          建议在提供一个类的构造器时,顺手加上它的无参构造器(这是一个好习惯)
 *
 *      9.构造器中是可以使用this关键字,this指向当前对象.但是构造器中的this有独特的用法
 *          在一个构造器中可以用this去调用另一个构造器
 *          语法:
 *              this(参数);
 *          不同数据类型的参数,指示不同的构造器
 *          这在很多时候是可以节约一些代码量的
 *          this调用别的构造器时，必须在第一行（只能用一次）
 *
 *       10.不同参数的构造器之间构成方法的重载,如果想要给两个String成员变量单独写构造器赋值是做不到的
 *
 *       11.类加载的过程仅有一次，但是new对象时构造器 new几个对象执行几次
 *
 *
 */
public class Demo {
    public static void main(String[] args) {
        /*//创建Teacher对象
        Teacher t = new Teacher();
        t.name = "张三";
        t.course = "Java";
        t.age = 18;

        Teacher t2 = new Teacher();
        t.name = "李四";
        t.course = "C++";
        t.age = 38;

        Teacher t3 = new Teacher();
        t.name = "老王2";
        t.course = "Python";
        t.age = 8;*/

        //使用有参构造器Teacher(name)创建对象
        Teacher t = new Teacher("法外狂徒-张三");
        System.out.println(t.name);

        Teacher t2 = new Teacher("张全蛋", "苹果质检员", 29);

        //Cannot resolve constructor 'Teacher()'
        Teacher t3 = new Teacher();
        Teacher t4 = new Teacher();
        Teacher t5 = new Teacher();
        Teacher t6 = new Teacher();


    }
}

class Teacher {
    String name = "老🐴";
    String course;
    int age;

    public void teach() {
        System.out.println("上课~");
    }

    //无参构造器
    public Teacher() {
        //空的方法体
        System.out.println("hello world!");
    }

    //有参构造器
    //给name赋值的有参构造器
    public Teacher(String name) {
        this.name = name;
    }

    //public Teacher(String course) {
    //    this.course = course;
    //}

    //使用快捷键alt+insert快速生成构造器
    public Teacher(int age) {
        this.age = age;
    }

    public Teacher(String name, String course) {
        this.name = name;
        this.course = course;
    }

    public Teacher(String name, String course, int age) {
        this(name, course);
        //Call to 'this()' must be first statement in constructor body
        //this(name);
        this.age = age;
    }
}
